<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>MSE 音频播放器 - FrameType=1</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 20px;
        }
        
        .container {
            background: white;
            border-radius: 15px;
            box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
            padding: 40px;
            max-width: 600px;
            width: 100%;
        }
        
        h1 {
            color: #333;
            margin-bottom: 10px;
            text-align: center;
            font-size: 28px;
        }
        
        .subtitle {
            text-align: center;
            color: #666;
            margin-bottom: 30px;
            font-size: 14px;
        }
        
        .player-section {
            background: #f8f9fa;
            border-radius: 10px;
            padding: 25px;
            margin-bottom: 25px;
        }
        
        audio {
            width: 100%;
            margin-bottom: 20px;
            border-radius: 5px;
        }
        
        .control-buttons {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 10px;
            margin-bottom: 20px;
        }
        
        button {
            padding: 12px 20px;
            border: none;
            border-radius: 5px;
            font-size: 14px;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s ease;
        }
        
        #playBtn {
            background: #667eea;
            color: white;
            grid-column: 1;
        }
        
        #playBtn:hover:not(:disabled) {
            background: #5568d3;
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
        }
        
        #stopBtn {
            background: #f093fb;
            color: white;
            grid-column: 2;
        }
        
        #stopBtn:hover:not(:disabled) {
            background: #e07eea;
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(240, 147, 251, 0.4);
        }
        
        button:disabled {
            opacity: 0.5;
            cursor: not-allowed;
        }
        
        .status-box {
            background: white;
            border-left: 4px solid #667eea;
            padding: 15px;
            border-radius: 5px;
            margin-bottom: 20px;
        }
        
        .status-label {
            color: #666;
            font-size: 12px;
            text-transform: uppercase;
            letter-spacing: 1px;
            margin-bottom: 5px;
        }
        
        #status {
            font-size: 16px;
            font-weight: 600;
            color: #333;
        }
        
        .progress-section {
            background: white;
            padding: 15px;
            border-radius: 5px;
            margin-bottom: 20px;
        }
        
        .progress-label {
            font-size: 12px;
            color: #666;
            margin-bottom: 8px;
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }
        
        .progress-bar {
            width: 100%;
            height: 6px;
            background: #e0e0e0;
            border-radius: 3px;
            overflow: hidden;
        }
        
        .progress-fill {
            height: 100%;
            background: linear-gradient(90deg, #667eea, #764ba2);
            width: 0%;
            transition: width 0.1s linear;
        }
        
        .time-info {
            font-size: 12px;
            color: #666;
            margin-top: 8px;
            text-align: center;
        }
        
        .info-box {
            background: #e3f2fd;
            border-left: 4px solid #2196f3;
            padding: 15px;
            border-radius: 5px;
            font-size: 13px;
            color: #1565c0;
            line-height: 1.6;
        }
        
        .error {
            background: #ffebee;
            border-left-color: #f44336;
            color: #c62828;
        }
        
        .success {
            background: #e8f5e9;
            border-left-color: #4caf50;
            color: #2e7d32;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>🎵 音频播放器</h1>
        <p class="subtitle">智能播放 FrameType=1 音频 (自动兼容 iOS)</p>
        
        <div class="player-section">
            <audio id="audioPlayer" controls></audio>
            
            <div class="control-buttons">
                <button id="playBtn">▶ 播放</button>
                <button id="stopBtn" disabled>⏹ 停止</button>
            </div>
            
            <div class="status-box">
                <div class="status-label">状态</div>
                <div id="status">准备就绪</div>
            </div>
            
            <div class="progress-section">
                <div class="progress-label">进度</div>
                <div class="progress-bar">
                    <div class="progress-fill" id="progressFill"></div>
                </div>
                <div class="time-info">
                    <span id="currentTime">00:00</span> / <span id="duration">00:00</span>
                </div>
            </div>
            
            <div class="info-box" id="infoBox">
                点击"播放"按钮开始播放音频...
            </div>
        </div>
    </div>
    <script src="js/audio2.js"></script>
    <script>
        // 从 audio.js 中提取 frameType=1 的音频数据
        const extractedAudioFrames = [];
        
        // 提取 frameType=1 的音频数据
        if (typeof audioData !== 'undefined' && Array.isArray(audioData)) {
            audioData.forEach((item, index) => {
                try {
                    // 跳过第一个数据（包含URL信息）和 frameType=0 的数据
                    if (index === 0 || !item.audioData || item.audioData.trim() === '') {
                        return;
                    }
                    
                    // 只处理 frameType="1" 的数据
                    if (item.frameType === "1" && item.audioData) {
                        extractedAudioFrames.push(item.audioData);
                        console.log(`提取第 ${extractedAudioFrames.length} 个音频帧`);
                    }
                } catch (e) {
                    console.error('处理音频数据项时出错:', e, item);
                }
            });
            console.log(`总共提取了 ${extractedAudioFrames.length} 个 frameType=1 的音频帧`);
        } else {
            console.error('未找到 audioData 或格式不正确');
        }

        const audio = document.getElementById('audioPlayer');
        const playBtn = document.getElementById('playBtn');
        const stopBtn = document.getElementById('stopBtn');
        const statusEl = document.getElementById('status');
        const infoBox = document.getElementById('infoBox');
        const progressFill = document.getElementById('progressFill');
        const currentTimeEl = document.getElementById('currentTime');
        const durationEl = document.getElementById('duration');

        let mediaSource = null;
        let sourceBuffer = null;
        let useDirectPlayback = false; // iOS等不支持MSE的设备使用直接播放

        // 转换 base64 字符串为 ArrayBuffer（参考 sseAudioPlayer1.js 的实现）
        function base64ToArrayBuffer(base64) {
            try {
                // 移除可能的空白字符
                const cleanBase64 = base64.trim();
                
                if (!cleanBase64) {
                    throw new Error('Base64 字符串为空');
                }
                
                const binaryString = atob(cleanBase64);
                const bytes = new Uint8Array(binaryString.length);
                for (let i = 0; i < binaryString.length; i++) {
                    bytes[i] = binaryString.charCodeAt(i);
                }
                return bytes.buffer;
            } catch (e) {
                console.error('Base64 解码失败:', e);
                throw e;
            }
        }

        // 检测是否支持MSE
        function checkMSESupport() {
            return false;
            // 检测iOS设备
            const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
            const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
            
            // MSE在iOS Safari上不可用
            if (isIOS || (isSafari && !window.MediaSource)) {
                return false;
            }
            
            // 检查MediaSource API和MIME类型支持
            if (!window.MediaSource || !MediaSource.isTypeSupported('audio/mpeg')) {
                return false;
            }
            
            return true;
        }
        
        // 直接播放模式：合并所有音频片段
        function initDirectPlayback() {
            try {
                updateStatus('正在合并音频片段...');
                infoBox.textContent = `准备合并 ${extractedAudioFrames.length} 个音频片段`;
                infoBox.className = 'info-box';
                
                // 将所有base64片段转换为二进制数据
                const chunks = [];
                let totalLength = 0;
                
                extractedAudioFrames.forEach((base64Data, index) => {
                    try {
                        const binaryString = atob(base64Data.trim());
                        const bytes = new Uint8Array(binaryString.length);
                        for (let i = 0; i < binaryString.length; i++) {
                            bytes[i] = binaryString.charCodeAt(i);
                        }
                        chunks.push(bytes);
                        totalLength += bytes.length;
                        
                        // 更新进度
                        const progress = Math.round(((index + 1) / extractedAudioFrames.length) * 100);
                        updateStatus(`合并中... ${progress}% (${index + 1}/${extractedAudioFrames.length})`);
                    } catch (e) {
                        console.error(`处理音频帧 ${index} 时出错:`, e);
                    }
                });
                
                // 合并所有片段
                const mergedAudio = new Uint8Array(totalLength);
                let offset = 0;
                chunks.forEach(chunk => {
                    mergedAudio.set(chunk, offset);
                    offset += chunk.length;
                });
                
                // 创建Blob并设置为音频源
                const blob = new Blob([mergedAudio], { type: 'audio/mpeg' });
                const url = URL.createObjectURL(blob);
                audio.src = url;
                
                updateStatus('音频加载完成，可以播放');
                infoBox.textContent = `已成功合并 ${extractedAudioFrames.length} 个音频片段 (${(blob.size / 1024 / 1024).toFixed(2)} MB)`;
                infoBox.className = 'info-box success';
                playBtn.disabled = false;
                
                // 当播放结束时清理URL对象
                audio.addEventListener('ended', () => {
                    URL.revokeObjectURL(url);
                });
                
            } catch (e) {
                showError(`直接播放模式失败: ${e.message}`);
                console.error('直接播放模式详细错误:', e);
            }
        }

        // 初始化 MSE
        function initializeMediaSource() {
            if (!window.MediaSource) {
                showError('您的浏览器不支持 MediaSource Extensions');
                return;
            }

            mediaSource = new MediaSource();
            const url = URL.createObjectURL(mediaSource);
            audio.src = url;

            mediaSource.addEventListener('sourceopen', handleSourceOpen);
            mediaSource.addEventListener('error', (e) => {
                showError(`MediaSource 错误: ${e.target.error}`);
            });
        }

        // 处理 sourceopen 事件
        function handleSourceOpen() {
            try {
                // MP3 的 MIME 类型和编解码器
                const mimeType = 'audio/mpeg';
                
                if (!MediaSource.isTypeSupported(mimeType)) {
                    showError(`浏览器不支持 ${mimeType}`);
                    return;
                }

                sourceBuffer = mediaSource.addSourceBuffer(mimeType);
                sourceBuffer.addEventListener('error', (e) => {
                    showError(`SourceBuffer 错误: ${e.target.error}`);
                });

                appendAudioData();
            } catch (e) {
                showError(`初始化失败: ${e.message}`);
            }
        }

        // 添加音频数据
        function appendAudioData() {
            try {
                if (extractedAudioFrames.length === 0) {
                    showError('没有找到可播放的音频数据（frameType=1）');
                    return;
                }
                
                updateStatus(`正在加载 ${extractedAudioFrames.length} 个音频片段...`);
                infoBox.textContent = `准备加载 ${extractedAudioFrames.length} 个音频片段`;
                infoBox.className = 'info-box';
                
                let dataIndex = 0;
                let appendedCount = 0;

                function appendNextFrame() {
                    if (sourceBuffer.updating) {
                        // 如果正在更新，稍后再试
                        setTimeout(appendNextFrame, 50);
                        return;
                    }
                    
                    if (dataIndex >= extractedAudioFrames.length) {
                        // 所有数据已添加
                        try {
                            if (mediaSource.readyState === 'open') {
                                mediaSource.endOfStream();
                                updateStatus('音频加载完成，可以播放');
                                infoBox.textContent = `已成功加载 ${appendedCount} 个音频片段，总时长约 ${formatTime(audio.duration || 0)}`;
                                infoBox.className = 'info-box success';
                                playBtn.disabled = false;
                            }
                        } catch (e) {
                            console.error('结束流时出错:', e);
                            showError(`结束流失败: ${e.message}`);
                        }
                        return;
                    }

                    try {
                        const base64Data = extractedAudioFrames[dataIndex];
                        const arrayBuffer = base64ToArrayBuffer(base64Data);
                        
                        if (arrayBuffer.byteLength > 0) {
                            sourceBuffer.appendBuffer(arrayBuffer);
                            appendedCount++;
                            dataIndex++;
                            
                            // 更新进度
                            const progress = Math.round((dataIndex / extractedAudioFrames.length) * 100);
                            updateStatus(`加载中... ${progress}% (${dataIndex}/${extractedAudioFrames.length})`);
                        } else {
                            console.warn(`跳过空音频帧: ${dataIndex}`);
                            dataIndex++;
                            setTimeout(appendNextFrame, 10);
                        }
                    } catch (e) {
                        console.error(`处理音频帧 ${dataIndex} 时出错:`, e);
                        dataIndex++; // 跳过有问题的帧
                        setTimeout(appendNextFrame, 10);
                    }
                }

                sourceBuffer.addEventListener('updateend', () => {
                    // 继续添加下一帧
                    setTimeout(appendNextFrame, 10);
                });
                
                sourceBuffer.addEventListener('error', (e) => {
                    console.error('SourceBuffer 错误:', e);
                    showError('音频缓冲区错误');
                });

                // 开始添加第一帧
                appendNextFrame();
            } catch (e) {
                showError(`添加音频数据失败: ${e.message}`);
                console.error('添加音频数据详细错误:', e);
            }
        }

        // 播放
        function play() {
            if (!audio.src) {
                updateStatus('正在初始化音频...');
                
                // 检测是否支持MSE
                if (checkMSESupport()) {
                    console.log('使用MSE模式播放');
                    useDirectPlayback = false;
                    initializeMediaSource();
                } else {
                    console.log('使用直接播放模式 (iOS兼容)');
                    useDirectPlayback = true;
                    initDirectPlayback();
                }
            } else {
                audio.play().catch(e => {
                    showError(`播放失败: ${e.message}`);
                });
            }
        }

        // 停止
        function stop() {
            audio.pause();
            audio.currentTime = 0;
            updateStatus('已停止');
            playBtn.disabled = false;
            stopBtn.disabled = true;
        }

        // 更新状态
        function updateStatus(message) {
            statusEl.textContent = message;
        }

        // 显示错误
        function showError(message) {
            updateStatus('出错');
            infoBox.textContent = message;
            infoBox.className = 'info-box error';
            playBtn.disabled = true;
        }

        // 格式化时间
        function formatTime(seconds) {
            const mins = Math.floor(seconds / 60);
            const secs = Math.floor(seconds % 60);
            return `${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
        }

        // 事件监听
        playBtn.addEventListener('click', play);
        stopBtn.addEventListener('click', stop);

        audio.addEventListener('play', () => {
            updateStatus('▶ 播放中...');
            playBtn.disabled = true;
            stopBtn.disabled = false;
            infoBox.textContent = '音频正在播放...';
            infoBox.className = 'info-box success';
        });

        audio.addEventListener('pause', () => {
            if (audio.currentTime === 0) {
                updateStatus('已停止');
            } else {
                updateStatus('⏸ 暂停');
            }
            playBtn.disabled = false;
            stopBtn.disabled = false;
        });

        audio.addEventListener('timeupdate', () => {
            currentTimeEl.textContent = formatTime(audio.currentTime);
            if (audio.duration) {
                progressFill.style.width = (audio.currentTime / audio.duration * 100) + '%';
            }
        });

        audio.addEventListener('loadedmetadata', () => {
            durationEl.textContent = formatTime(audio.duration);
            updateStatus('准备就绪');
        });

        audio.addEventListener('ended', () => {
            updateStatus('播放完成');
            playBtn.disabled = false;
            stopBtn.disabled = true;
            infoBox.textContent = '音频播放完成！';
            infoBox.className = 'info-box success';
        });

        audio.addEventListener('error', (e) => {
            showError(`音频播放错误: ${e.target.error.message}`);
        });

        // 初始化
        updateStatus('准备就绪');
    </script>
</body>
</html>
